import { HttpException, Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource, In } from 'typeorm';
import { User } from 'src/entities/user.entity';
import { UserFollow } from 'src/entities/user-follow.entity';
import { InjectRedis } from '@nestjs-modules/ioredis';
import Redis from 'ioredis';

@Injectable()
export class FollowService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    @InjectRepository(UserFollow)
    private readonly userFollowRepository: Repository<UserFollow>,
    private readonly dataSource: DataSource, // 用于事务
    @InjectRedis() private readonly redis: Redis,
  ) {}

  // 关注用户
  async followUser(followerId: number, followedId: number): Promise<void> {
    if (followerId === followedId) {
      throw new HttpException('不能关注自己', 400);
    }

    // 不能重复关注
    const follow = await this.userFollowRepository.findOne({
      where: { followerId, followedId },
    });
    if (follow) {
      throw new HttpException('已关注该用户', 400);
    }

    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 检查用户是否存在
      const follower = await this.userRepository.findOneBy({ id: followerId });
      const followed = await this.userRepository.findOneBy({ id: followedId });
      if (!follower || !followed) {
        throw new NotFoundException('用户不存在');
      }

      // 插入关注关系
      await queryRunner.manager.save(UserFollow, {
        followerId,
        followedId,
        created_at: new Date(),
      });

      // 更新用户计数
      await queryRunner.manager.update(
        User,
        { id: followerId },
        { following_count: () => 'following_count + 1' },
      );
      await queryRunner.manager.update(
        User,
        { id: followedId },
        { follower_count: () => 'follower_count + 1' },
      );

      await queryRunner.commitTransaction();

      // Redis 操作
      await this.redis.setnx(`user:${followerId}:following_count`, 0);
      await this.redis.setnx(`user:${followedId}:follower_count`, 0);

      const timestamp = Math.floor(Date.now() / 1000); // 改为秒级
      await Promise.all([
        this.redis.zadd(
          `user:${followerId}:following`,
          timestamp,
          followedId.toString(),
        ),
        this.redis.zadd(
          `user:${followedId}:followers`,
          timestamp,
          followerId.toString(),
        ),
        this.redis.incr(`user:${followerId}:following_count`),
        this.redis.incr(`user:${followedId}:follower_count`),
      ]);
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }

  // 取消关注
  async unfollowUser(followerId: number, followedId: number): Promise<void> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 删除关注关系
      const deleteResult = await queryRunner.manager.delete(UserFollow, {
        followerId,
        followedId,
      });

      if (deleteResult.affected === 0) {
        throw new NotFoundException('Follow relationship not found');
      }

      // 更新用户计数
      await queryRunner.manager.update(
        User,
        { id: followerId },
        { following_count: () => 'GREATEST(following_count - 1, 0)' },
      );
      await queryRunner.manager.update(
        User,
        { id: followedId },
        { follower_count: () => 'GREATEST(follower_count - 1, 0)' },
      );

      await queryRunner.commitTransaction();

      // Redis 操作
      await Promise.all([
        this.redis.zrem(`user:${followerId}:following`, followedId.toString()),
        this.redis.zrem(`user:${followedId}:followers`, followerId.toString()),
        this.redis.decr(`user:${followerId}:following_count`),
        this.redis.decr(`user:${followedId}:follower_count`),
      ]);
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }

  // 获取关注列表（带分页）
  async getFollowingList(
    userId: number,
    page: number = 1,
    limit: number = 10,
  ): Promise<{
    items: Array<{
      followedId: number;
      followed: User;
      created_at: Date;
    }>;
    total: number;
    page: number;
    limit: number;
    totalPages: number;
  }> {
    const redisKey = `user:${userId}:following`;
    const exists = await this.redis.exists(redisKey); // 检查缓存是否存在
    if (!exists) {
      // 从数据库加载并缓存
      const follows = await this.userFollowRepository.find({
        where: { followerId: userId },
        order: { created_at: 'DESC' },
      });
      const pipeline = this.redis.pipeline();
      follows.forEach((follow) => {
        pipeline.zadd(
          redisKey,
          Math.floor(follow.created_at.getTime() / 1000),
          follow.followedId.toString(),
        );
      });
      await pipeline.exec();
    }
  
    // 获取总数
    const total = await this.redis.zcard(redisKey);
    const start = (page - 1) * limit;
    const stop = start + limit - 1;
  
    const result = await this.redis.zrevrange(
      redisKey,
      start,
      stop,
      'WITHSCORES',
    );
  
    const followingItems = [];
    const followedUserIds = [];
    const timestampMap = new Map();
  
    // 处理结果
    for (let i = 0; i < result.length; i += 2) {
      const followedId = parseInt(result[i], 10);
      const timestamp = parseInt(result[i + 1], 10);
      
      followedUserIds.push(followedId);
      timestampMap.set(followedId, timestamp);
    }
  
    // 如果有关注用户，则查询用户详情
    if (followedUserIds.length > 0) {
      const followedUsers = await this.userRepository.findBy({
        id: In(followedUserIds),
      });
      
      // 按照从Redis获取的顺序构建结果
      for (const followedId of followedUserIds) {
        const followedUser = followedUsers.find(user => user.id === followedId);
        if (followedUser) {
          followingItems.push({
            followedId,
            followed: followedUser,
            created_at: new Date(timestampMap.get(followedId) * 1000), // 从秒转换为毫秒
          });
        }
      }
    }
  
    const totalPages = Math.ceil(total / limit);
  
    return {
      items: followingItems,
      total,
      page,
      limit,
      totalPages,
    };
  }

  async getFollowersList(
    userId: number,
    page: number = 1,
    limit: number = 10,
  ): Promise<{
    items: Array<{
      followerId: number;
      follower: User;
      created_at: Date;
    }>;
    total: number;
    page: number;
    limit: number;
    totalPages: number;
  }> {
    const redisKey = `user:${userId}:followers`;
    const exists = await this.redis.exists(redisKey); // 检查缓存是否存在
    if (!exists) {
      // 从数据库加载并缓存
      const followers = await this.userFollowRepository.find({
        where: { followedId: userId },
        order: { created_at: 'DESC' },
      });
      const pipeline = this.redis.pipeline();
      followers.forEach((follow) => {
        pipeline.zadd(
          redisKey,
          Math.floor(follow.created_at.getTime() / 1000),
          follow.followerId.toString(),
        );
      });
      await pipeline.exec();
    }
  
    // 获取总数
    const total = await this.redis.zcard(redisKey);
    const start = (page - 1) * limit;
    const stop = start + limit - 1;
  
    const result = await this.redis.zrevrange(
      redisKey,
      start,
      stop,
      'WITHSCORES',
    );
  
    const followerItems = [];
    const followerUserIds = [];
    const timestampMap = new Map();
  
    // 处理结果
    for (let i = 0; i < result.length; i += 2) {
      const followerId = parseInt(result[i], 10);
      const timestamp = parseInt(result[i + 1], 10);
      
      followerUserIds.push(followerId);
      timestampMap.set(followerId, timestamp);
    }
  
    // 如果有粉丝用户，则查询用户详情
    if (followerUserIds.length > 0) {
      const followerUsers = await this.userRepository.findBy({
        id: In(followerUserIds),
      });
      
      // 按照从Redis获取的顺序构建结果
      for (const followerId of followerUserIds) {
        const followerUser = followerUsers.find(user => user.id === followerId);
        if (followerUser) {
          followerItems.push({
            followerId,
            follower: followerUser,
            created_at: new Date(timestampMap.get(followerId) * 1000), // 从秒转换为毫秒
          });
        }
      }
    }
  
    const totalPages = Math.ceil(total / limit);
  
    return {
      items: followerItems,
      total,
      page,
      limit,
      totalPages,
    };
  }

  // 获取用户关注的所有用户ID
async getFollowingIds(userId: number): Promise<number[]> {
  const redisKey = `user:${userId}:following`;
  
  // 先尝试从Redis获取
  const followingIds = await this.redis.zrange(redisKey, 0, -1);
  
  // 如果Redis没有数据，从数据库加载
  if (followingIds.length === 0) {
    const follows = await this.userFollowRepository.find({
      where: { followerId: userId },
    });
    
    // 缓存到Redis
    if (follows.length > 0) {
      const pipeline = this.redis.pipeline();
      follows.forEach((follow) => {
        pipeline.zadd(
          redisKey,
          Math.floor(follow.created_at.getTime() / 1000),
          follow.followedId.toString(),
        );
      });
      await pipeline.exec();
      
      // 返回从数据库获取的ID列表
      return follows.map(follow => follow.followedId);
    }
    
    return [];
  }
  
  // 将字符串ID转换为数字并返回
  return followingIds.map(id => parseInt(id, 10));
}
}
